Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
53.85% |
7 / 13 |
CRAP | |
76.60% |
108 / 141 |
| ProductPropertiesNormalizer | |
0.00% |
0 / 1 |
|
53.85% |
7 / 13 |
79.78 | |
76.60% |
108 / 141 |
| __construct | |
100.00% |
1 / 1 |
1 | |
100.00% |
5 / 5 |
|||
| normalize | |
0.00% |
0 / 1 |
12.03 | |
94.12% |
48 / 51 |
|||
| getLabel | |
100.00% |
1 / 1 |
4 | |
100.00% |
7 / 7 |
|||
| supportsNormalization | |
100.00% |
1 / 1 |
2 | |
100.00% |
2 / 2 |
|||
| getAllParentsValues | |
0.00% |
0 / 1 |
12.00 | |
0.00% |
0 / 8 |
|||
| getAncestors | |
100.00% |
1 / 1 |
2 | |
100.00% |
11 / 11 |
|||
| getAncestorsIds | |
100.00% |
1 / 1 |
2 | |
100.00% |
5 / 5 |
|||
| getAncestorsCodes | |
100.00% |
1 / 1 |
2 | |
100.00% |
5 / 5 |
|||
| getAncestorsLabels | |
0.00% |
0 / 1 |
9.30 | |
72.73% |
16 / 22 |
|||
| getLocalizableAndScopableLabels | |
0.00% |
0 / 1 |
20.00 | |
0.00% |
0 / 8 |
|||
| getScopableLabels | |
0.00% |
0 / 1 |
12.00 | |
0.00% |
0 / 6 |
|||
| getLocalizableLabels | |
100.00% |
1 / 1 |
3 | |
100.00% |
7 / 7 |
|||
| ensureAdditionalNormalizersAreValid | |
0.00% |
0 / 1 |
4.12 | |
50.00% |
2 / 4 |
|||
| <?php | |
| declare(strict_types=1); | |
| namespace Akeneo\Pim\Enrichment\Component\Product\Normalizer\Indexing\ProductAndProductModel; | |
| use Akeneo\Channel\Component\Repository\ChannelRepositoryInterface; | |
| use Akeneo\Channel\Component\Repository\LocaleRepositoryInterface; | |
| use Akeneo\Pim\Enrichment\Component\Product\Model\EntityWithFamilyVariantInterface; | |
| use Akeneo\Pim\Enrichment\Component\Product\Model\ProductInterface; | |
| use Akeneo\Pim\Enrichment\Component\Product\Model\ProductModelInterface; | |
| use Akeneo\Pim\Enrichment\Component\Product\Normalizer\Standard\Product\PropertiesNormalizer as StandardPropertiesNormalizer; | |
| use Symfony\Component\Serializer\Normalizer\NormalizerInterface; | |
| use Symfony\Component\Serializer\SerializerAwareInterface; | |
| use Symfony\Component\Serializer\SerializerAwareTrait; | |
| /** | |
| * Transform the properties of products and variant product objects (fields and product values) | |
| * to the "indexing_product_and_product_model" format. | |
| * | |
| * @author Samir Boulil <samir.boulil@akeneo.com> | |
| * @copyright 2017 Akeneo SAS (http://www.akeneo.com) | |
| * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) | |
| */ | |
| class ProductPropertiesNormalizer implements NormalizerInterface, SerializerAwareInterface | |
| { | |
| use SerializerAwareTrait; | |
| private const FIELD_COMPLETENESS = 'completeness'; | |
| private const FIELD_FAMILY_VARIANT = 'family_variant'; | |
| private const FIELD_IN_GROUP = 'in_group'; | |
| private const FIELD_ID = 'id'; | |
| private const FIELD_PARENT = 'parent'; | |
| private const FIELD_ANCESTORS = 'ancestors'; | |
| private const FIELD_CATEGORIES_OF_ANCESTORS = 'categories_of_ancestors'; | |
| /** @var ChannelRepositoryInterface */ | |
| private $channelRepository; | |
| /** @var LocaleRepositoryInterface */ | |
| private $localeRepository; | |
| /** @var NormalizerInterface[] */ | |
| private $additionalDataNormalizers; | |
| public function __construct( | |
| ChannelRepositoryInterface $channelRepository, | |
| LocaleRepositoryInterface $localeRepository, | |
| iterable $additionalDataNormalizers = [] | |
| ) { | |
| $this->channelRepository = $channelRepository; | |
| $this->localeRepository = $localeRepository; | |
| $this->ensureAdditionalNormalizersAreValid($additionalDataNormalizers); | |
| $this->additionalDataNormalizers = $additionalDataNormalizers; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function normalize($product, $format = null, array $context = []) | |
| { | |
| if (!$this->serializer instanceof NormalizerInterface) { | |
| throw new \LogicException('Serializer must be a normalizer'); | |
| } | |
| $data = []; | |
| $data[self::FIELD_ID] = 'product_' .(string) $product->getId(); | |
| $data[StandardPropertiesNormalizer::FIELD_IDENTIFIER] = $product->getIdentifier(); | |
| $data[StandardPropertiesNormalizer::FIELD_CREATED] = $this->serializer->normalize( | |
| $product->getCreated(), | |
| $format | |
| ); | |
| $data[StandardPropertiesNormalizer::FIELD_UPDATED] = $this->serializer->normalize( | |
| $product->getUpdated(), | |
| $format | |
| ); | |
| $data[StandardPropertiesNormalizer::FIELD_FAMILY] = $this->serializer->normalize( | |
| $product->getFamily(), | |
| $format | |
| ); | |
| $data[StandardPropertiesNormalizer::FIELD_ENABLED] = (bool) $product->isEnabled(); | |
| $data[StandardPropertiesNormalizer::FIELD_CATEGORIES] = $product->getCategoryCodes(); | |
| $ancestorsCategories = []; | |
| if ($product->isVariant() && null !== $product->getParent()) { | |
| $ancestorsCategories = $product->getParent()->getCategoryCodes(); | |
| } | |
| $data[self::FIELD_CATEGORIES_OF_ANCESTORS] = $ancestorsCategories; | |
| $data[StandardPropertiesNormalizer::FIELD_GROUPS] = $product->getGroupCodes(); | |
| foreach ($product->getGroupCodes() as $groupCode) { | |
| $data[self::FIELD_IN_GROUP][$groupCode] = true; | |
| } | |
| $data[self::FIELD_COMPLETENESS] = !$product->getCompletenesses()->isEmpty() | |
| ? $this->serializer->normalize( | |
| $product->getCompletenesses(), | |
| ProductModelNormalizer::INDEXING_FORMAT_PRODUCT_AND_MODEL_INDEX, | |
| $context | |
| ) : []; | |
| $familyVariantCode = null; | |
| if ($product->isVariant()) { | |
| $familyVariant = $product->getFamilyVariant(); | |
| $familyVariantCode = null !== $familyVariant ? $familyVariant->getCode() : null; | |
| } | |
| $data[self::FIELD_FAMILY_VARIANT] = $familyVariantCode; | |
| $parentCode = null; | |
| if ($product->isVariant() && null !== $product->getParent()) { | |
| $parentCode = $product->getParent()->getCode(); | |
| } | |
| $data[self::FIELD_PARENT] = $parentCode; | |
| $data[StandardPropertiesNormalizer::FIELD_VALUES] = !$product->getValues()->isEmpty() | |
| ? $this->serializer->normalize( | |
| $product->getValues(), | |
| ProductModelNormalizer::INDEXING_FORMAT_PRODUCT_AND_MODEL_INDEX, | |
| $context | |
| ) : []; | |
| $data[self::FIELD_ANCESTORS] = $this->getAncestors($product); | |
| $data[StandardPropertiesNormalizer::FIELD_LABEL] = $this->getLabel( | |
| $data[StandardPropertiesNormalizer::FIELD_VALUES], | |
| $product | |
| ); | |
| foreach ($this->additionalDataNormalizers as $normalizer) { | |
| $data = array_merge($data, $normalizer->normalize($product, $format, $context)); | |
| } | |
| return $data; | |
| } | |
| /** | |
| * Get label of the given product | |
| * | |
| * @param array $values | |
| * @param ProductInterface $product | |
| * | |
| * @return array | |
| */ | |
| private function getLabel(array $values, ProductInterface $product): array | |
| { | |
| $family = $product->getFamily(); | |
| if (null === $family || null === $family->getAttributeAsLabel()) { | |
| return []; | |
| } | |
| $valuePath = sprintf('%s-text', $family->getAttributeAsLabel()->getCode()); | |
| if (!isset($values[$valuePath])) { | |
| return []; | |
| } | |
| return $values[$valuePath]; | |
| } | |
| /** | |
| * {@inheritdoc} | |
| */ | |
| public function supportsNormalization($data, $format = null) | |
| { | |
| return $data instanceof ProductInterface | |
| && ProductModelNormalizer::INDEXING_FORMAT_PRODUCT_AND_MODEL_INDEX === $format; | |
| } | |
| /** | |
| * Normalizes all the values of a product model and its parents. | |
| * | |
| * @param null|ProductModelInterface $productModel | |
| * @param array $context | |
| * | |
| * @return mixed | |
| */ | |
| private function getAllParentsValues($productModel, array $context) : array | |
| { | |
| if (null === $productModel || $productModel->getValues()->isEmpty()) { | |
| return []; | |
| } | |
| $productModelNormalizedValues = $this->serializer->normalize( | |
| $productModel->getValues(), | |
| ProductModelNormalizer::INDEXING_FORMAT_PRODUCT_AND_MODEL_INDEX, | |
| $context | |
| ); | |
| return array_merge( | |
| $productModelNormalizedValues, | |
| $this->getAllParentsValues($productModel->getParent(), $context) | |
| ); | |
| } | |
| /** | |
| * @param \Akeneo\Pim\Enrichment\Component\Product\Model\ProductInterface $product | |
| * | |
| * @return array | |
| */ | |
| private function getAncestors(ProductInterface $product): array | |
| { | |
| $ancestorsIds = []; | |
| $ancestorsCodes = []; | |
| $ancestorsLabels = []; | |
| if ($product->isVariant()) { | |
| $ancestorsIds = $this->getAncestorsIds($product); | |
| $ancestorsCodes = $this->getAncestorsCodes($product); | |
| $ancestorsLabels = $this->getAncestorsLabels($product); | |
| } | |
| $ancestors = [ | |
| 'ids' => $ancestorsIds, | |
| 'codes' => $ancestorsCodes, | |
| 'labels' => $ancestorsLabels, | |
| ]; | |
| return $ancestors; | |
| } | |
| /** | |
| * @param EntityWithFamilyVariantInterface $entityWithFamilyVariant | |
| * | |
| * @return array | |
| */ | |
| private function getAncestorsIds(EntityWithFamilyVariantInterface $entityWithFamilyVariant): array | |
| { | |
| $ancestorsIds = []; | |
| while (null !== $parent = $entityWithFamilyVariant->getParent()) { | |
| $ancestorsIds[] = 'product_model_' . $parent->getId(); | |
| $entityWithFamilyVariant = $parent; | |
| } | |
| return $ancestorsIds; | |
| } | |
| /** | |
| * @param EntityWithFamilyVariantInterface $entityWithFamilyVariant | |
| * | |
| * @return array | |
| */ | |
| private function getAncestorsCodes(EntityWithFamilyVariantInterface $entityWithFamilyVariant) | |
| { | |
| $ancestorsCodes = []; | |
| while (null !== $parent = $entityWithFamilyVariant->getParent()) { | |
| $ancestorsCodes[] = $parent->getCode(); | |
| $entityWithFamilyVariant = $parent; | |
| } | |
| return $ancestorsCodes; | |
| } | |
| /** | |
| * Retrieves ancestors labels for each locales and channels. | |
| * | |
| * @param EntityWithFamilyVariantInterface $entity | |
| * | |
| * @return array | |
| */ | |
| private function getAncestorsLabels(EntityWithFamilyVariantInterface $entity): array | |
| { | |
| $family = $entity->getFamily(); | |
| if (null === $family) { | |
| return []; | |
| } | |
| $attributeAsLabel = $family->getAttributeAsLabel(); | |
| if (null === $attributeAsLabel) { | |
| return []; | |
| } | |
| $ancestorsLabels = []; | |
| $attributeCodeAsLabel = $attributeAsLabel->getCode(); | |
| switch (true) { | |
| case $attributeAsLabel->isScopable() && $attributeAsLabel->isLocalizable(): | |
| $ancestorsLabels = $this->getLocalizableAndScopableLabels($entity, $attributeCodeAsLabel); | |
| break; | |
| case $attributeAsLabel->isScopable(): | |
| $ancestorsLabels = $this->getScopableLabels($entity, $attributeCodeAsLabel); | |
| break; | |
| case $attributeAsLabel->isLocalizable(): | |
| $ancestorsLabels = $this->getLocalizableLabels($entity, $attributeCodeAsLabel); | |
| break; | |
| default: | |
| $value = $entity->getValue($attributeCodeAsLabel); | |
| if (null !== $value) { | |
| $ancestorsLabels['<all_channels>']['<all_locales>'] = $value->getData(); | |
| } | |
| break; | |
| } | |
| return $ancestorsLabels; | |
| } | |
| /** | |
| * @param EntityWithFamilyVariantInterface $entity | |
| * @param string $attributeCodeAsLabel | |
| * | |
| * @return array | |
| */ | |
| private function getLocalizableAndScopableLabels( | |
| EntityWithFamilyVariantInterface $entity, | |
| string $attributeCodeAsLabel | |
| ): array { | |
| $ancestorsLabels = []; | |
| $localeCodes = $this->localeRepository->getActivatedLocaleCodes(); | |
| foreach ($this->channelRepository->getChannelCodes() as $channelCode) { | |
| foreach ($localeCodes as $localeCode) { | |
| $value = $entity->getValue($attributeCodeAsLabel, $localeCode, $channelCode); | |
| if (null !== $value) { | |
| $ancestorsLabels[$channelCode][$localeCode] = $value->getData(); | |
| } | |
| } | |
| } | |
| return $ancestorsLabels; | |
| } | |
| /** | |
| * @param EntityWithFamilyVariantInterface $entity | |
| * @param string $attributeCodeAsLabel | |
| * | |
| * @return array | |
| */ | |
| private function getScopableLabels(EntityWithFamilyVariantInterface $entity, string $attributeCodeAsLabel): array | |
| { | |
| $ancestorsLabels = []; | |
| foreach ($this->channelRepository->getChannelCodes() as $channelCode) { | |
| $value = $entity->getValue($attributeCodeAsLabel, null, $channelCode); | |
| if (null !== $value) { | |
| $ancestorsLabels[$channelCode]['<all_locales>'] = $value->getData(); | |
| } | |
| } | |
| return $ancestorsLabels; | |
| } | |
| /** | |
| * @param EntityWithFamilyVariantInterface $entity | |
| * @param string $attributeCodeAsLabel | |
| * | |
| * @return array | |
| */ | |
| private function getLocalizableLabels(EntityWithFamilyVariantInterface $entity, string $attributeCodeAsLabel): array | |
| { | |
| $ancestorsLabels = []; | |
| $localeCodes = $this->localeRepository->getActivatedLocaleCodes(); | |
| foreach ($localeCodes as $localeCode) { | |
| $value = $entity->getValue($attributeCodeAsLabel, $localeCode); | |
| if (null !== $value) { | |
| $ancestorsLabels['<all_channels>'][$localeCode] = $value->getData(); | |
| } | |
| } | |
| return $ancestorsLabels; | |
| } | |
| private function ensureAdditionalNormalizersAreValid(iterable $additionalNormalizers): void | |
| { | |
| foreach ($additionalNormalizers as $normalizer) { | |
| if (! $normalizer instanceof NormalizerInterface) { | |
| throw new \InvalidArgumentException('$normalizer is not a Normalizer'); | |
| } | |
| } | |
| } | |
| } |